/*
Author - Ido
*/
#include "BigNumber.h"
#include <regex>
#include <math.h>
#include <stdlib.h>
#include <sstream>

/*
 validate string 
*/
bool big_number::validate( string str)
{
	regex txt_regex(valstr);
	return regex_match( str, txt_regex);
}

/*
 Calculate the needed array size
*/
void big_number::calcArraySize( int size, int dotIndex)
{
	int integerSize;
	if ( dotIndex == string::npos)
	{
		// no dot in the string
		integerSize = (int)ceil(size/(double)9);
		if( bnflag)
			_fractionalPart = 1; // for big_number 
		else
			_fractionalPart = 0; // gor big_integer
	}
	else
	{
		// found dot in string 
		integerSize = (int)ceil((dotIndex)/(double)9);
		_fractionalPart  = (int)ceil((size-dotIndex-1)/(double)9);
	}

	// if integer was only 0
	if ( integerSize == 0 )
		integerSize++;

	_arr_size = integerSize + _fractionalPart;
}

/*
 parse integer part of string
*/
void big_number::createIntegerPart( string str)
{
	int arrayIndex;
	string numStr;

	if ( str.empty())
	{
		_num_array[0] = 0;
		return;
	}

	arrayIndex = _arr_size - _fractionalPart - 1;
	while( arrayIndex >= 0)
	{
		if( str.size() > 9)
		{
			numStr = str.substr( str.size()-9, str.size());
			str = str.substr( 0, str.size()-9);
		}
		else
		{
			numStr = str;
		}
		stringstream( numStr) >> _num_array[arrayIndex];
		arrayIndex--;
	}
}

/*
 parese fracture of string
*/
void big_number::createFracturePart( string str)
{
	int i, arrayIndex;
	string numStr;

	if ( _fractionalPart == 0)
		return;

	arrayIndex = _arr_size - _fractionalPart;
	if ( str.empty())
	{
		_num_array[arrayIndex] = 0;
		return;
	}
		
	while( arrayIndex < _arr_size)
	{
		if( str.size() > 9)
		{
			numStr = str.substr( 0, 9);
			str = str.substr( 9, str.size());
		}
		else
		{
			numStr = str;
			if(  str.size() < 9)
			{
				for(i=0; i < (9-(int)str.size()); i++)
					numStr += "0";
			}	
		}
		stringstream( numStr) >> _num_array[arrayIndex];
		arrayIndex++;
	}
}

/*
 set sign false for negetive
*/
void big_number::setSign( string str)
{
	if ( str.find("-") == 0)
	{
		_sign = false;
	}
	else 
	{
		_sign = true;
	}
	 
}

/*
 clean streing from 0
*/
void cleanInput(string *str){
	size_t dotIndex;
	while ((*str).find("0") == 0)
		(*str) = (*str).substr(1);

	dotIndex = (*str).find(".");
	
	if ( dotIndex != string::npos)
	{
		while ((*str).find_last_of("0") == (*str).size()-1)
			(*str) = (*str).substr(0,(*str).size()-1);
		
		dotIndex = (*str).find(".");
	}

	if ( dotIndex == ((*str).size()-1))
		(*str) = (*str).substr(0,(*str).size()-1);
}

/*
 parse string to array
*/
void big_number::strToArray( string str)
{
	size_t dotIndex;
	string tmpPart, numStr;

	if ( !validate( str)) //is string valid
		throw exception(); //TODO def execption not valid

	setSign( str);

	if( str.find("-") == 0 || str.find("+") == 0)
		str = str.substr(1);
	cleanInput(&str);
	dotIndex = str.find(".");
	calcArraySize( str.size(), dotIndex);

	_num_array = (unsigned long*) malloc( _arr_size*sizeof(unsigned long));
	
	if ( _num_array == NULL)
		throw exception(); //TODO def execption can't allocate memory

	if ( dotIndex == string::npos)
		dotIndex = str.size();

	createIntegerPart( str.substr(0, dotIndex));

	if ( ++dotIndex > str.size())
		dotIndex = str.size();

	createFracturePart( str.substr(dotIndex, str.size()));
}

/**
* init local variables
**/
void big_number::init( string str)
{
	// validation prefix
	valstr = BIGNUMBERREX;

	// is big number (using in construction of decimal part)
	bnflag = true;

	// parse string to array
	strToArray( str);
}